namespace TfsExtensions.Build.Helper
{
    using System;
    using System.Configuration;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Xml;
    using System.Reflection;

    /// <summary>
    /// Helper Class for Configuration
    /// </summary>
    public sealed class ConfigurationHelper
    {
        /// <summary>
        /// Prevents a default instance of the <see cref="ConfigurationHelper"/> class from being created. 
        /// Private constructor ensures class cannot be instantiated.
        /// </summary>
        private ConfigurationHelper()
        {
        }

        /// <summary>
        /// Reads the config section key value.
        /// </summary>
        /// <param name="configFilePath">
        /// The config file path.
        /// </param>
        /// <param name="sectionName">
        /// Name of the section.
        /// </param>
        /// <param name="keyName">
        /// Name of the key.
        /// </param>
        /// <returns>
        /// The read config section key value.
        /// </returns>
        public static string ReadConfigSectionKeyValue(string configFilePath, string sectionName, string keyName)
        {
            string value = string.Empty;
            try
            {
                if (File.Exists(configFilePath) && !string.IsNullOrEmpty(sectionName) && !string.IsNullOrEmpty(keyName))
                {
                    var configFileMap = new ExeConfigurationFileMap();
                    configFileMap.ExeConfigFilename = configFilePath;
                    Configuration configurationFile = ConfigurationManager.OpenMappedExeConfiguration(
                        configFileMap, 
                        ConfigurationUserLevel.None);

                    var sectionToRead = configurationFile.GetSection(sectionName) as AppSettingsSection;
                    if (sectionToRead != null)
                    {
                        value = sectionToRead.Settings[keyName].Value;
                    }
                }
                else if (!File.Exists(configFilePath))
                {
                    try
                    {
                        EventLog.WriteEntry(
                            "ReadConfigSectionKeyValue()", 
                            " Unable to open configuation file  : " + configFilePath);
                    }
                    catch (InvalidOperationException invalidEx)
                    {
                        // Placed for debugging purposes.
                        // System.Windows.Forms.MessageBox.Show("Brd.VS2005 ReadConfigSectionKeyValue()", " Unable to open configuation file  : " + configFilePath);
                        LoggingHelper2.LogError(
                            "ConfigurationHelper.ReadConfigSectionKeyValue", 
                            invalidEx.Message, 
                            string.Empty);
                    }
                }
            }
            catch (ConfigurationErrorsException configEx)
            {
                LoggingHelper2.LogError("ConfigurationHelper.ReadConfigSectionKeyValue", configEx.Message, string.Empty);
            }
            catch (Exception ex)
            {
                LoggingHelper2.LogError("ConfigurationHelper.ReadConfigSectionKeyValue", ex.Message, string.Empty);
            }

            return value;
        }

        /// <summary>
        /// Gets the configured log file path.
        /// </summary>
        /// <param name="logType">
        /// Type of the log.
        /// </param>
        /// <param name="configFilePath">
        /// The config file path.
        /// </param>
        /// <param name="formatterName">
        /// Name of the formatter.
        /// </param>
        /// <returns>
        /// The get configured log file path.
        /// </returns>
        public static string GetConfiguredLogFilePath(
            LoggingCategory logType, 
            string configFilePath, 
            out string formatterName)
        {
            string logFilePath = string.Empty;
            formatterName = string.Empty;
            try
            {
                string sectionName = logType.ToString();
                string xpathQuery = string.Empty;
                if (!string.IsNullOrEmpty(sectionName) && !string.IsNullOrEmpty(configFilePath))
                {
                    var configFileXml = new XmlDocument();
                    configFileXml.Load(configFilePath);

                    xpathQuery = string.Format(
                        CultureInfo.InvariantCulture, 
                        "configuration/loggingConfiguration/categorySources/add[@name='{0}']/listeners/add", 
                        sectionName);

                    XmlNode logTypeNode = configFileXml.SelectSingleNode(xpathQuery);
                    if (logTypeNode != null)
                    {
                        string listenerName = logTypeNode.Attributes["name"].Value;
                        if (!string.IsNullOrEmpty(listenerName))
                        {
                            xpathQuery = string.Format(
                                CultureInfo.InvariantCulture, 
                                "configuration/loggingConfiguration/listeners/add[@name='{0}']", 
                                listenerName);
                            XmlNode listenerTypeNode = configFileXml.SelectSingleNode(xpathQuery);
                            if (listenerTypeNode != null)
                            {
                                string listenerTypeName = listenerTypeNode.Attributes["type"].Value;

                                // Check if File Logging is being used.
                                if (
                                    listenerTypeName.ToUpper(CultureInfo.InvariantCulture).IndexOf(
                                        "Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener"
                                            .ToUpper(CultureInfo.InvariantCulture), 
                                            StringComparison.OrdinalIgnoreCase) >=
                                    0)
                                {
                                    string configuredPath = listenerTypeNode.Attributes["fileName"].Value;
                                    if (!string.IsNullOrEmpty(configFilePath))
                                    {
                                        logFilePath = GetFullLogFilePath(configuredPath);
                                    }

                                    if (listenerTypeNode.Attributes["formatter"] != null)
                                    {
                                        formatterName = listenerTypeNode.Attributes["formatter"].Value;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (XmlException xmlEx)
            {
                LoggingHelper2.LogError("ConfigurationHelper.GetConfiguredLogFilePath", xmlEx.Message, string.Empty);
            }
            catch (Exception ex)
            {
                LoggingHelper2.LogError("ConfigurationHelper.GetConfiguredLogFilePath", ex.Message, string.Empty);
            }

            return logFilePath;
        }

        /// <summary>
        /// Get the absolute log file path.
        /// </summary>
        /// <param name="path">The path of the file.</param>
        /// <returns>The get full log file path.</returns>
        private static string GetFullLogFilePath(string path)
        {
            string fullPath = string.Empty;
            if (!string.IsNullOrEmpty(path))
            {
                // Case for full path
                if (path.IndexOf(":", StringComparison.OrdinalIgnoreCase) == 1)
                {
                    fullPath = path;
                }
                else if (path.StartsWith(@"\\", StringComparison.OrdinalIgnoreCase))
                {
                    // Case of network path 
                    fullPath = path;
                }
                else
                {
                    if (path.StartsWith(@"\", StringComparison.OrdinalIgnoreCase))
                    {
                        path = path.Remove(0, 1);
                    }

                    string location = Assembly.GetExecutingAssembly().Location.Substring(0, Assembly.GetExecutingAssembly().Location.LastIndexOf(@"\", StringComparison.Ordinal));
                    fullPath = Path.Combine(location, path);
                }
            }

            return fullPath;
        }
    }
}